﻿using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
using System.Linq.Expressions;
using System.Security.Principal;

namespace Yelper.API {
    public class YelperDataService : DataService<YelperEntities> {        
        public static void InitializeService(DataServiceConfiguration config) {
            /* Access Rules */
            config.SetEntitySetAccessRule("UserDetails", EntitySetRights.None);
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetServiceOperationAccessRule("*", ServiceOperationRights.AllRead);
            
            config.SetEntitySetAccessRule("Yelps", EntitySetRights.WriteAppend | EntitySetRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
            config.UseVerboseErrors = true;
        }


        /// <summary>
        /// This function gets called when someone tries to add an yelp. We'll perform an Authentication check here to make sure the user has the required privileges
        /// </summary>
        /// <param name="yelp"></param>
        /// <param name="updateOperations"></param>
        [ChangeInterceptor("Yelps")]
        public void OnYelpsChange(Yelp yelp, UpdateOperations updateOperations) {
            CheckUserAuthenticated();
            if (updateOperations == UpdateOperations.Add) {
                var principal = (HttpContext.Current.User as GenericPrincipal);
                yelp.User = CurrentDataSource.Users.Where(x => x.Username == principal.Identity.Name).Single();
                yelp.YelpDate = DateTime.UtcNow;                
            } else {
                throw new Exception("Only add is allowed");                
            }
        }


        /// <summary>
        /// A custom service operation
        /// </summary>
        /// <returns>Public timeline</returns>
        [WebGet]
        public IQueryable<Yelp> PublicTimeline() {
            return CurrentDataSource.Yelps.OrderByDescending(y => y.YelpDate);
        }


        /// <summary>
        /// A custom service operation
        /// </summary>
        /// <returns>Mentions of the current user</returns>
        [WebGet]
        public IQueryable<Yelp> MyMentions() {
            CheckUserAuthenticated();
            var principal = (HttpContext.Current.User as GenericPrincipal);
            var user = CurrentDataSource.Users.Where(x => x.Username == principal.Identity.Name).Single();            
            return user.MentionedIn.AsQueryable();             
        }

        /// <summary>
        /// A custom service operation
        /// </summary>
        /// <returns>Timeline of the current user</returns>
        [WebGet]
        public IQueryable<Yelp> MyTimeline() {                        
            CheckUserAuthenticated();
            var principal = (HttpContext.Current.User as GenericPrincipal);            
            var user = CurrentDataSource.Users.Where(x => x.Username == principal.Identity.Name).Single();
            return user.Idols.SelectMany(u => u.Yelps).Concat(user.Yelps).AsQueryable();
        }

        /// <summary>
        /// Check whether or not the current user is authenticated. In case he isn't a DataServiceException is thrown (401 Unauthorized)
        /// </summary>
        private void CheckUserAuthenticated() {            
            if (string.IsNullOrEmpty((HttpContext.Current.User as GenericPrincipal).Identity.Name)) {
                HttpContext.Current.Response.Headers.Add("WWW-Authenticate", "Basic");
                throw new DataServiceException(401, "401 Unauthorized");
            }
        }
    }
}
